package handler

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"os"
	"pan/common"
	"pan/config"
	"pan/db"
	"pan/meta"
	"pan/mq"
	"pan/store/ceph"
	"pan/store/oss"
	"pan/util"
	"strconv"
	"time"
)

// UploadFileHandler: 上传处理
func UploadFileHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method == "GET" {
		// 返回上传页面
		data, err := ioutil.ReadFile("./static/view/index.html")
		if err != nil {
			io.WriteString(w, http.StatusText(http.StatusInternalServerError))
			return
		}
		io.WriteString(w, string(data))
	} else if r.Method == "POST" {
		file, head, err := r.FormFile("file")
		if err != nil {
			fmt.Printf("get data fail, err:%s\n", err.Error())
			return
		}
		defer file.Close()
		fileMeta := meta.FileMeta{
			FileName: head.Filename,
			FileSize: 0,
			Location: "upload/" + head.Filename,
			UploadAt: time.Now().Format("2006-01-02 15:04:05"),
		}
		newFile, err := os.Create(fileMeta.Location)
		if err != nil {
			fmt.Printf("create file fail, err:%s\n", err.Error())
			return
		}
		defer newFile.Close()
		fileMeta.FileSize, err = io.Copy(newFile, file)
		if err != nil {
			fmt.Printf("save file fail, err:%s\n", err.Error())
			return
		}
		newFile.Seek(0, 0)
		fileMeta.FileHash = util.FileSha1(newFile)
		fmt.Println(fileMeta)
		if config.CurrentStoreType == common.StoreCeph {
			// 文件写入Ceph存储
			data, _ := ioutil.ReadAll(newFile)
			cephPath := config.CephRootDir + fileMeta.FileHash
			_ = ceph.PutObject("userfile", cephPath, data)
			fileMeta.Location = cephPath
		} else if config.CurrentStoreType == common.StoreOSS {
			// 文件写入OSS存储
			ossPath := config.OSSRootDir + fileMeta.FileHash
			// 判断写入OSS为同步还是异步
			if !config.AsyncTransferEnable {
				// TODO: 设置oss中的文件名，方便指定文件名下载
				err = oss.Bucket().PutObject(ossPath, newFile)
				if err != nil {
					log.Println(err.Error())
					// errCode := -5
					return
				}
				fileMeta.Location = ossPath
			} else {
				// 写入异步转移任务队列
				data := mq.TransferData{
					FileHash:      fileMeta.FileHash,
					CurLocation:   fileMeta.Location,
					DestLocation:  ossPath,
					DestStoreType: common.StoreOSS,
				}
				pubData, _ := json.Marshal(data)
				pubSuc := mq.Publish(
					config.TransExchangeName,
					config.TransOSSRoutingKey,
					pubData,
				)
				if !pubSuc {
					// TODO: 当前发送转移信息失败，稍后重试
					fmt.Println(pubSuc)
				}
			}
		}
		// 同时将文件写入ceph
		// newFile.Seek(0, 0)
		// data, _ := ioutil.ReadAll(newFile)
		// cephPath := "/ceph/" + fileMeta.FileHash
		// ceph.PutObject("userfile", cephPath, data)
		// fileMeta.Location = cephPath
		// oss
		// ossPath := "oss/" + fileMeta.FileHash
		// oss.Bucket().PutObject(ossPath, newFile)
		// fileMeta.Location = ossPath
		// meta.UpdateFileMeta(fileMeta)
		meta.UpdateFileMetaToDB(fileMeta)
		r.ParseForm()
		username := r.Form.Get("username")
		res := db.OnUserFileUploadFinished(username, fileMeta.FileHash, fileMeta.FileName, fileMeta.FileSize)
		if res {
			resp := util.RespMsg{
				Code: 0,
				Msg:  "上传成功",
			}
			w.Write(resp.JSONBytes())
			// http.Redirect(w, r, "/file/upload/suc", http.StatusFound)
		} else {
			w.WriteHeader(http.StatusInternalServerError)
		}
	}
}

// UploadStructHandler: 上传成功处理
func UploadSucHandler(w http.ResponseWriter, r *http.Request) {
	io.WriteString(w, "Upload Finish")
}

// GetFileMetaHandler: 获取文件元信息
func GetFileMetaHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fileHash := r.Form["filehash"][0]
	fileMeta := meta.GetFileMetaFromDB(fileHash)
	data, err := json.Marshal(fileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(data)
}

// QueryFileHandler: 查询用户文件
func QueryFileHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	limit, err := strconv.Atoi(r.Form.Get("limit"))
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	username := r.Form.Get("username")
	userFiles, err := db.QueryUserFileMetas(username, limit)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	data, err := json.Marshal(userFiles)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(data)
}

// DownloadFileHandler: 文件下载
func DownloadFileHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fileSha1 := r.Form.Get("filehash")
	fileMeta := meta.GetFileMetaFromDB(fileSha1)
	file, err := os.Open(fileMeta.Location)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	defer file.Close()
	data, err := ioutil.ReadAll(file)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Header().Set("Content-Type", "application/octect-stream")
	w.Header().Set("content-disposition", "attacment;filename=\""+fileMeta.FileName+"\"")
	w.Write(data)
}

// DownloadURLHandler: 文件下载地址
func DownloadURLHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fileSha1 := r.Form.Get("filehash")
	fileMeta, _ := db.GetFileMeta(fileSha1)
	fileURL := oss.DownloadURL(fileMeta.FileAddr.String)
	w.Write([]byte(fileURL))
}

// UpdateFileMetaHandler: 修改文件元信息
func UpdateFileMetaHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	opType := r.Form.Get("op")
	if opType != "0" {
		w.WriteHeader(http.StatusForbidden)
		return
	}
	if r.Method != "POST" {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	fileHash := r.Form.Get("filehash")
	newFileName := r.Form.Get("filename")
	curFileMeta := meta.GetFileMetaFromDB(fileHash)
	curFileMeta.FileName = newFileName
	meta.UpdateFileMeta(curFileMeta)
	data, err := json.Marshal(curFileMeta)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(data)
	w.WriteHeader(http.StatusOK)
}

// DeleteFileHandler: 删除文件及元信息
func DeleteFileHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	fileHash := r.Form.Get("filehash")
	fileMeta := meta.GetFileMetaFromDB(fileHash)
	os.Remove(fileMeta.Location)
	meta.RemoveFileMeta(fileHash)
	w.WriteHeader(http.StatusOK)
}

// TryFastUploadHandler: 尝试秒传
func TryFastUploadHandler(w http.ResponseWriter, r *http.Request) {
	r.ParseForm()
	username := r.Form.Get("username")
	fileHash := r.Form.Get("filehash")
	fileName := r.Form.Get("filename")
	fileSize, err := strconv.ParseInt(r.Form.Get("filesize"), 10, 64)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	fileMeta := meta.GetFileMetaFromDB(fileHash)
	if fileMeta.FileName == "" {
		resp := util.RespMsg{
			Code: -1,
			Msg:  "秒传失败,请访问普通接口",
		}
		w.Write(resp.JSONBytes())
		return
	}
	suc := db.OnUserFileUploadFinished(username, fileHash, fileName, fileSize)
	if suc {
		resp := util.RespMsg{
			Code: 0,
			Msg:  "秒传成功",
		}
		w.Write(resp.JSONBytes())
		return
	}
	resp := util.RespMsg{
		Code: 0,
		Msg:  "秒传失败，稍后重试",
	}
	w.Write(resp.JSONBytes())
}
